package apple.ui.awt;

import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;

import org.apache.log4j.Logger;

import apple.core.KeyboardDecoder;

public class Keyboard implements KeyListener {

   static Logger logger = Logger.getLogger(Keyboard.class);

   private KeyboardDecoder keyboardDecoder;

   public void setKeyboardDecoder(KeyboardDecoder keyboardDecoder) {
      this.keyboardDecoder = keyboardDecoder;
   }

   /*
    * (non-Javadoc)
    * 
    * @see java.awt.event.KeyListener#keyPressed(java.awt.event.KeyEvent)
    */
   @Override
   public void keyPressed(KeyEvent e) {
      int keyCode = e.getKeyCode();
      Integer asciiCode = null;

      switch (keyCode) {

      case KeyEvent.VK_BACK_SPACE:
         asciiCode = 0x7F;
         logger.debug(String.format("remapping key: %02X to %02X", keyCode,
               asciiCode));
         break;

      case KeyEvent.VK_LEFT:
         asciiCode = 0x08;
         logger.debug(String.format("remapping key: %02X to %02X", keyCode,
               asciiCode));
         break;

      case KeyEvent.VK_TAB:
         asciiCode = keyCode;
         break;

      case KeyEvent.VK_DOWN:
         asciiCode = 0x0A;
         logger.debug(String.format("remapping key: %02X to %02X", keyCode,
               asciiCode));
         break;

      case KeyEvent.VK_UP:
         asciiCode = 0x0B;
         logger.debug(String.format("remapping key: %02X to %02X", keyCode,
               asciiCode));
         break;

      case KeyEvent.VK_ENTER:
         asciiCode = 0x0D;
         logger.debug(String.format("remapping key: %02X to %02X", keyCode,
               asciiCode));
         break;

      case KeyEvent.VK_RIGHT:
         asciiCode = 0x15;
         logger.debug(String.format("remapping key: %02X to %02X", keyCode,
               asciiCode));
         break;

      case KeyEvent.VK_ESCAPE:
         asciiCode = keyCode;
         break;

      case KeyEvent.VK_SPACE:
         asciiCode = keyCode;
         break;

      case KeyEvent.VK_QUOTE:
         asciiCode = 0x27;
         logger.debug(String.format("remapping key: %02X to %02X", keyCode,
               asciiCode));
         asciiCode = e.isShiftDown() ? 0x22 : asciiCode;
         break;

      case KeyEvent.VK_COMMA:
         asciiCode = e.isShiftDown() ? 0x3C : keyCode;
         break;

      case KeyEvent.VK_MINUS:
         if (e.isControlDown()) {
            asciiCode = 0x1F;
         } else {
            asciiCode = e.isShiftDown() ? 0x5F : keyCode;
         }
         break;

      case KeyEvent.VK_PERIOD:
         asciiCode = e.isShiftDown() ? 0x3E : keyCode;
         break;

      case KeyEvent.VK_SLASH:
         asciiCode = e.isShiftDown() ? 0x3F : keyCode;
         break;

      case KeyEvent.VK_0:
         asciiCode = e.isShiftDown() ? 0x29 : keyCode;
         break;

      case KeyEvent.VK_1:
         asciiCode = e.isShiftDown() ? 0x21 : keyCode;
         break;

      case KeyEvent.VK_2:
         if (e.isControlDown()) {
            asciiCode = 0x00;
         } else {
            asciiCode = e.isShiftDown() ? 0x40 : keyCode;
         }
         break;

      case KeyEvent.VK_3:
         asciiCode = e.isShiftDown() ? 0x23 : keyCode;
         break;

      case KeyEvent.VK_4:
         asciiCode = e.isShiftDown() ? 0x24 : keyCode;
         break;

      case KeyEvent.VK_5:
         asciiCode = e.isShiftDown() ? 0x25 : keyCode;
         break;

      case KeyEvent.VK_6:
         if (e.isControlDown()) {
            asciiCode = 0x1E;
         } else {
            asciiCode = e.isShiftDown() ? 0x5E : keyCode;
         }
         break;

      case KeyEvent.VK_7:
         asciiCode = e.isShiftDown() ? 0x26 : keyCode;
         break;

      case KeyEvent.VK_8:
         asciiCode = e.isShiftDown() ? 0x2A : keyCode;
         break;

      case KeyEvent.VK_9:
         asciiCode = e.isShiftDown() ? 0x28 : keyCode;
         break;

      case KeyEvent.VK_SEMICOLON:
         asciiCode = e.isShiftDown() ? 0x3A : keyCode;
         break;

      case KeyEvent.VK_EQUALS:
         asciiCode = e.isShiftDown() ? 0x2B : keyCode;
         break;

      case KeyEvent.VK_OPEN_BRACKET:
         if (e.isControlDown()) {
            asciiCode = 0x1B;
         } else {
            asciiCode = e.isShiftDown() ? 0x7B : keyCode;
         }
         break;

      case KeyEvent.VK_BACK_SLASH:
         if (e.isControlDown()) {
            asciiCode = 0x1C;
         } else {
            asciiCode = e.isShiftDown() ? 0x7C : keyCode;
         }
         break;

      case KeyEvent.VK_CLOSE_BRACKET:
         if (e.isControlDown()) {
            asciiCode = 0x1D;
         } else {
            asciiCode = e.isShiftDown() ? 0x7D : keyCode;
         }
         break;

      case KeyEvent.VK_BACK_QUOTE:
         asciiCode = 0x60;
         logger.debug(String.format("remapping key: %02X to %02X", keyCode,
               asciiCode));
         asciiCode = e.isShiftDown() ? 0x7E : asciiCode;
         break;

      case KeyEvent.VK_A:
      case KeyEvent.VK_B:
      case KeyEvent.VK_C:
      case KeyEvent.VK_D:
      case KeyEvent.VK_E:
      case KeyEvent.VK_F:
      case KeyEvent.VK_G:
      case KeyEvent.VK_H:
      case KeyEvent.VK_I:
      case KeyEvent.VK_J:
      case KeyEvent.VK_K:
      case KeyEvent.VK_L:
      case KeyEvent.VK_M:
      case KeyEvent.VK_N:
      case KeyEvent.VK_O:
      case KeyEvent.VK_P:
      case KeyEvent.VK_Q:
      case KeyEvent.VK_R:
      case KeyEvent.VK_S:
      case KeyEvent.VK_T:
      case KeyEvent.VK_U:
      case KeyEvent.VK_V:
      case KeyEvent.VK_W:
      case KeyEvent.VK_X:
      case KeyEvent.VK_Y:
      case KeyEvent.VK_Z:
         if (e.isControlDown()) {
            asciiCode = keyCode - 0x40;
         } else {
            asciiCode = e.isShiftDown() ? keyCode : keyCode + 0x20;
         }
         break;

      default:
         logger.debug(String.format("key pressed: keycode=%02X (ignored)",
               keyCode));
         break;
      }

      if (asciiCode != null) {
         logger.debug(String.format("key pressed: ascii code=%02X", asciiCode));
         keyboardDecoder.setAsciiCodeAndStrobe(asciiCode.byteValue());
         keyboardDecoder.setKeyDown(true);
      }
   }

   /*
    * (non-Javadoc)
    * 
    * @see java.awt.event.KeyListener#keyTyped(java.awt.event.KeyEvent)
    */
   @Override
   public void keyTyped(KeyEvent e) {
      /*
       * Ignore. All keyboard input is handled with keyPressed() method.
       */
   }

   /*
    * (non-Javadoc)
    * 
    * @see java.awt.event.KeyListener#keyReleased(java.awt.event.KeyEvent)
    */
   @Override
   public void keyReleased(KeyEvent e) {
      /*
       * There are two minor problems with this implementation:
       * 
       * 1. If more than one key are down and then one is released, this will
       * set keyDown=false even though other keys are still down.
       * 
       * 2. The release of any key, not just those keys enumerated in
       * keyPressed(), will set keyDown=false.
       */
      keyboardDecoder.setKeyDown(false);
   }
}
